package cmdoptions

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

// supportTypes = ["b", "d", "s"]
// func contains(s []int, e int) bool {
//     for _, a := range s {
//         if a == e {
//             return true
//         }
//     }
//     return false
// }

var (
	ErrOptionNotSet       = errors.New("option not set")
	ErrOptionInvalidValue = errors.New("option value invalid")
	ErrOptionInvalidType  = errors.New("option type invalid")
	ErrOptionParseValue   = errors.New("option parse value error")
)

const (
	OptionTypeBool    = "b"
	OptionTypeDecimal = "d"
	OptionTypeString  = "s"
)

type CmdOptions struct {
	optTypes  map[string]string
	optValues map[string]interface{}
}

func NewCmdOptions() CmdOptions {
	result := CmdOptions{
		optTypes:  make(map[string]string),
		optValues: make(map[string]interface{}),
	}
	return result
}

func (co *CmdOptions) SetOption(optName string, optType string, defaultValue interface{}) {
	fmt.Print(optName, optType, defaultValue)
}

// "l:b,p:d,d:s", "-l -p 8080 -d /usrs/wenjing"
func (co *CmdOptions) Parse(format string, options string) error {
	//这里错误处理先不做了，保证输入正确。
	fs := strings.Split(format, ",")
	for _, v := range fs {
		kv := strings.Split(v, ":")
		co.optTypes[kv[0]] = kv[1]
	}

	optionsString := strings.Split(options, "-")
	for _, optVal := range optionsString {
		//跳过第0个选项
		if len(optVal) == 0 {
			continue
		}

		opt := optVal[0:1]
		val := ""
		if len(optVal) > 1 {
			val = optVal[2:]
		}

		// co.optValues[option] = value
		err := co.parseValue(opt, val)
		if err != nil {
			return err
		}
	}
	return nil
}

func (co *CmdOptions) parseValue(option string, value string) error {
	switch co.optTypes[option] {
	case OptionTypeBool:
		if len(value) == 0 {
			co.optValues[option] = true
			return nil
		}

		res, err := strconv.ParseBool(value)
		if err != nil {
			return fmt.Errorf("Parse %s to bool error, %w", value, ErrOptionParseValue)
		}
		co.optValues[option] = res
		return nil

	case OptionTypeDecimal:
		if len(value) == 0 {
			return fmt.Errorf("option %s should has a value, %w", option, ErrOptionParseValue)
		}

		res, err := strconv.Atoi(value)
		if err != nil {
			return fmt.Errorf("Parse %s to int error, %w", value, ErrOptionParseValue)
		}
		co.optValues[option] = res
		return nil
	case OptionTypeString:
		if len(value) == 0 {
			return fmt.Errorf("option %s should has a value, %w", option, ErrOptionParseValue)
		}
		co.optValues[option] = value
		return nil
	default:
		panic("unsupport option type " + option)
	}
}

func (co *CmdOptions) GetBool(optionName string) (bool, error) {
	opt, ok := co.optTypes[optionName]
	if !ok {
		return false, fmt.Errorf("unrecognize option %s , %w", optionName, ErrOptionNotSet)
	}

	if opt != OptionTypeBool {
		return false, fmt.Errorf("option is not bool type, %w", ErrOptionInvalidType)
	}

	v, ok := co.optValues[optionName]
	//未设置布尔类型时，默认值为false
	if !ok {
		return false, nil
	}

	return v.(bool), nil
}

func (co *CmdOptions) GetDecimal(optionName string) (int, error) {
	opt, ok := co.optTypes[optionName]
	if !ok {
		return 0, fmt.Errorf("unrecognize option %s , %w", optionName, ErrOptionNotSet)
	}

	if opt != OptionTypeDecimal {
		return 0, fmt.Errorf("option is not int type, %w", ErrOptionInvalidValue)
	}

	v, ok := co.optValues[optionName]
	//未设置布尔类型时，默认值为false
	if !ok {
		return 0, fmt.Errorf("value not set, %w", ErrOptionInvalidValue)
	}

	return v.(int), nil
}

func (co *CmdOptions) GetString(optionName string) (string, error) {
	opt, ok := co.optTypes[optionName]
	if !ok {
		return "", fmt.Errorf("unrecognize option %s , %w", optionName, ErrOptionNotSet)
	}

	if opt != OptionTypeString {
		return "", fmt.Errorf("option is not string type, %w", ErrOptionInvalidValue)
	}

	v, ok := co.optValues[optionName]
	//未设置布尔类型时，默认值为false
	if !ok {
		return "", fmt.Errorf("value not set, %w", ErrOptionInvalidValue)
	}

	return v.(string), nil
}

func (co *CmdOptions) GetStringArray(optionName string) []string {
	return []string{}
}

// func (*CmdOptions) Option(optName string) interface{} {
// 	return 0
// }
